Phase 8 — Calling

Markers: being worked on, implemented and waiting to be reviewed, done, closed by deciding not to do it, ? open decision, unmarked = planned.

What this arc is for

Two users can call each other with audio or video from the messages screen. The call runs between the two browsers; Yioop carries the offers, the answers and the candidates between them. A call between two people at home usually cannot be made directly, since each is behind a router that lets nothing in unasked, so a relay has to stand where both can reach it. Yioop ships one, TurnSite, and nothing starts it: GROUP_CALL_ICE_SERVERS is null, so the browser is handed no relay at all and the call has only direct paths to try. Calls worked for Chris when coturn was set up beside the site and the setting was filled in by hand. This arc brings Yioop own relay up, wires it to the code that is already there, and then debugs that code with a relay in place rather than without one.

Plan

  1. The relay is a program the site can start and stop. src/executables/TurnServer.php builds TurnSite from settings in Config.php and is started the way the mail server is, by CrawlDaemon. The machines screen draws a row for it with its log and one switch, and the model says whether it is running. What it listens on, who may use it and the ports it hands out are TURN_BIND, TURN_PORT, TURN_REALM, TURN_USER, TURN_SECRET and TURN_RELAY_PORTS.
  2. A call is told where the relay is. MessageComponent writes GROUP_CALL_ICE_SERVERS into the page as literal JavaScript for the browser to hand RTCPeerConnection, and a site owner writes those objects by hand today. Where the relay is running, the site builds that entry itself from what the relay is listening on, with the name and secret a browser needs, so turning the relay on is all a site owner does.
    1. The screen naming a relay is drawn the way Mail Services is. The Video Call Services box now adds a relay with the same [+] button, list and Remove marks the mail domains use, and the controls that name one are shown only under the two choices that hand a browser a named relay. Its Add button had no label of its own in any language, so the screen printed the name of the missing string; that name and a Remove title are now written in the locale file. The wiring behind the list had been written into the page three times over, of which the last stood and the other two were dead, and one copy is now kept.
    2. A call reaches the site's own relay again, and a test says so. The address a browser is handed was worked out by a call to baseUrl written in the wrong namespace, so a site that turned its relay on died on an undefined function. The call now names the namespace that declares it.
    3. Each test case names the calling choice it stands for. The relay cases were written before a site owner could choose which relays a call may use, so they read the site's own setting and failed under the default. callRelays takes that choice as a parameter and callServiceMode gives what a running site picked. A case for calling turned off was added, and the whole class had been dying silently on the fatal above.
    4. The fieldset carries a mark that opens its help page. Its legend now holds the help mark the other groups of settings have, and the page it opens, Video Call Services, is delivered beside the patch as wiki source for Chris to paste in.
    5. A saved calling choice comes back rather than reverting. The screen read the choice from the named settings, which hold what the settings file said when the server started, so on a server that stays up a saved choice showed as Disable Calling until a restart. The screen reads the profile it already reads on every request, and the messages screen reads the same file through the profile model, so neither waits on a restart to see what was saved.
    6. The Server Settings render methods build the link addresses they use. Splitting render into one method per group of settings left three of them reading $base_url, $pre_base_url, $admin_url and $token_string, which were local to render, so under a PHP that warns on it the page carried Undefined variable notices for the restart, clear-cache, domain-routing and mail-log links. An adminUrls helper builds the four from the token in $data, and each method that draws such a link calls it, so no value is read across a method boundary.
  3. A call is made over the relay and watched. Two browsers driven at once, a call placed, and what each side sent and read written down in order: the offer, the answer, the candidates, and which of them the relay carried. That is what says whether the code as it stands works with a relay, and it is the record a failing call is read against.
    1. The call button is shown when calling is turned on. The button was drawn only where the hand-set GROUP_CALL_ICE_SERVERS constant held servers, so a site that turned calling on through the Servers screen and let its own relay supply the servers drew no button at all. The controller passes CALL_ENABLED, true for any mode other than off, and the conversation header shows the controls on that.
    2. A call is watched from the browser console. A call-trace logger writes each step of a call, the channel it came over, and the seconds since the first step, so two browsers' consoles read together show where a call stops. It names each signaling message sent and read, each local candidate and whether it is a relay one, and the connection state as it changes. It is turned on for a page when the site's debug level asks for developer messages.
    3. Call events ride the WebSocket when one is open. The WebSocket push carried new messages only, so a call's offers, answers and candidates fell to the event stream even where a socket was open for messages. The push now drains the waiting call events each pass and sends them in the same envelope the browser already reads, with the event stream left as the fall back.
    4. A call event is read once and none is dropped. The time nextCallEvent handed back came out shorter than the column held, so passed back as the next cutoff it matched its own row again and the same event was read twice, and a call never moved past its first answer. The time is now written out to the microsecond. Two events timed to the same microsecond also shared the time that is half the events' primary key, so one was dropped; since two people in a call may write at once under a web server that forks a process per request, the insert is now tried and its result read, and where nothing was written the time is moved on and the insert tried again, so a lost race is caught rather than guessed at.
  4. The first try is made to work. A call rings, fails, and works when tried again. With the relay in place and a working call written down, the failing one is reproduced against it and fixed. A call that cannot connect says so on both screens rather than leaving them waiting.
  5. Other work, grouped by what it touched. Each is a bug Chris reported from his own site while the calling work above was going on, and each went out as its own patch. They are gathered here by the part of Yioop they concern rather than listed one by one.
    1. The call relay was made reachable, durable and cheap. It listened where no browser could reach it, handed out an address the far browser could not use, and did not come back after a restart. A second call reused a closed connection, a call being rung timed out before anyone picked up, and an answer built the wrong way was refused by Safari. The relay now carries a packet without paying a disk write for it.
    2. The messages screen shows who is there and who is calling. A contact who is signed in wears a green border, the activity pulses while a call waits and the reader is elsewhere, and a calling contact's name pulses and gains controls to take or turn down the call. Both pulses stop where a reader has asked for less movement. The writing box is dropped when no contact is chosen, and the notice that stands in its place sits in the middle of the pane.
    3. Mail leaves the site, arrives whole, and reaches the right folder. Every lookup of where to deliver was going out malformed, so nothing sent left the site at all. Beyond that: an attachment arrives, an uploaded file keeps its own bytes, mail this server delivered to itself is neither called insecure nor sent to junk, a bare name on the same site resolves, and a message whose parts are separated by a name standing inside a longer one, or which stops part way through a separator, shows its words rather than a stray separator. The mail server can check a password again and logs its heartbeat to one file.
    4. Wiki pages read and edit as they should. A presentation is read as a slide deck by all four parsers, loads the slide engine, and previews as its slides laid out one after another; picking words in that preview finds them where they were written. A Git page draws again, an article page can be made, and the controls above an edit screen are one row that says what it is, with the nav bar naming the settings, resources and history views and the return mark going back to editing.
    5. Media lists and uploads hold up under real files. Dropping two items uploads them, a larger upload over a secure connection finishes, a folder lists quietly when a named file never arrived, a thumbnail inside a folder is served rather than the source, and viewing a video reads its figures. A group page loads and a heavier mail message is read where memory used to run out.
    6. The podcast updater downloads again and says what it decided. It was dying before it reached a podcast at all. A forced update now names the folders it was asked for and why it passed over each source, fetches every item's page again rather than trusting its own record, and asks for the folder its own page fills rather than one numbered zero.
    7. Names are offered as somebody types. The api answers a request for the names extending what has been typed, drawn from users, groups and roles, and the contact box on the messages screen and the role and group boxes on Manage Users all offer them. One control stands under the contact box where two stood. The names would not draw at first: a warning printed ahead of the answer stopped the browser reading it, and the box was a search box, beside which a browser built on WebKit draws nothing from a list of choices. The two controls on the user edit form that read Add now read as a plus, keeping the words for a reader who cannot see them. The names are drawn by Yioop rather than handed to the browser as a list of choices: Firefox never showed them where Safari and Chrome did, and four attempts at finding what Firefox wanted all failed, so the browser is no longer asked. The three fields share one drawn list, which reads the same everywhere and needs nothing of the browser but a place to put it. The list falls below the box rather than over it, each name reads in bold with what it is beneath in lighter letters and a line between one name and the next, the letter that first reaches three asks at once while later letters wait, and leaving the field and coming back shows the same names again.
    8. A resource being edited names itself and gains two marks. A line above the controls names the file and opens it as a visitor reads it. A mark downloads the file, and a file of figures gains a mark that swaps it between its rows and a chart. The marks read the same way on a narrow screen.
    9. A file of a page that lists files opens in the writing box. Opening one drew the page's list of files instead of the file, because the page's kind was read from where the file's settings are. The kind now rides in a field of its own, and more kinds of file open in the box.
    10. Settings, roles and locales keep what they are told. A password requirement turned off stays off, a modifier added to a role is kept and its removing mark reads as a button, a locale whose settings file this PHP will not read no longer breaks the strings screen, and the writing mode is explained once. The memory lines say what is in use rather than what has been claimed, and several screens build the models they use rather than dying reaching for them.
    11. The Save As mark is drawn to match its neighbors and asks for a name in a plain dialog. The mark now wears the floppy the plain save wears, with a small yellow pencil over its corner. It is measured at the same box and margins as Save and the keeping mark. The dialog is a plain browser prompt, which is how the mail screens already ask for one name.
      1. Only the messages screen asks whether somebody called. Every signed-in page was asking every few seconds, which cost a steady stream of requests. The menu no longer hands other pages the address to ask. The messages screen alone watches for a waiting call now.
      2. Two dev scripts gain the checks the last cycle showed were missing. A settle now takes a waiting patch only when the shown message names that patch. The devlog check counts words per added sentence and refuses one past the limit. Both gaps had let a fault reach a delivery.
      3. The Save As mark is refined and the media pencil opens the file. Save As now shows on the grid screen too. A name with a folder mark is refused in the dialog. A file looked at opens in the writing box from the pencil, where its kind is one the box takes.
    12. A picture kept with a page is edited on a canvas in the edit screen. Opening an image resource draws it on a canvas fitted to the screen. A row of controls above offers the size, a quarter turn, a mirror, and drawing tools. A save reads the canvas and writes it back over the file.
      1. The controls set the size and turn, mirror, and draw on the picture. Width and height fields resize it, and marks turn and mirror it. A tool draws a line, a box, a circle, an arrow or text. A step back undoes the last mark.
      2. A save writes the canvas back over the file. The picture is sent as its own kind and replaces the resource. A new picture is made from the file list at a size the reader gives.
      3. The editor is reached from the picture and from the pencil beside it. Both open the same canvas, and the pencil shows only where the page is being edited.
    13. A cached page with a field missing no longer warns or dies. A stored summary without an address, a robot name, a kind, or a time set off a warning on every read of it. Those fields now take a default. A stored page holding something other than text killed the request at the dom reader; it is taken only when it is text.
    14. The two rows of controls on a page of files share a line. The wiki row and the file row sit side by side where the window is wide enough. The wiki row drops above the file row where it is not. The box holding both is marked on such a page and lays them out.
    15. The index caches answer to the memory the serving process has. They were bounded by how many entries they held, not how large those were, so the always-on server held over a gigabyte in them. The allowance now takes a share of the process limit as well. The caches are given up when the process nears that limit.